package main

import (
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/orm"
	_ "github.com/go-sql-driver/mysql"
	"gowork/beegoToken/model"

	"fmt"
	//"fmt"
	//"strconv"
	_ "gowork/beegoToken/cors"
	"github.com/dgrijalva/jwt-go"
	_ "gowork/beegoToken/filter"
	"time"
)

type Many struct{
	beego.Controller
}

type ProductType struct{
	Id int `orm:"pk;auto"`
	Name string 
	//ProductList []*Product `orm:"reverse(many)"`

}

type Product struct{
	Id int `orm:"pk;auto"`
	Name string 
	Type *ProductType `orm:"rel(fk)"`
	//MealList []*Meal `orm:"reverse(many)"`
}

type ProjectType struct{
	Id int `orm:"pk;auto"`
	Name string 
	//ProjectList []*Project `orm:"reverse(many)"`
}

type Project struct{
	Id int `orm:"pk;auto"`
	Name string
	Type *ProjectType `orm:"rel(fk)"`
	//MealList []*Meal `orm:"reverse(many)"`

}

type Meal struct{
	Id int `orm:"pk;auto"`
	Name string 
	ProjectList []*Project `orm:"rel(m2m)"`
	ProductList []*Product `orm:"rel(m2m)"`
	//Memberlist []*Member `orm:"reverse(many)"`
}

type Member struct{
	Id int `orm:"pk;auto"`
	Name string
	Age int
	Sex int
	Level int
	Meallist []*Meal `orm:"rel(m2m)"`
	CreatedAt time.Time `orm:"auto_now_add;type(datetime)"`
	UpdatedAt time.Time `orm:"auto_now;type(datetime)"`
}

// MyClaims 自定义声明结构体并内嵌jwt.StandardClaims
// jwt包自带的jwt.StandardClaims只包含了官方字段
// 我们这里需要额外记录一个username字段，所以要自定义结构体
// 如果想要保存更多信息，都可以添加到这个结构体中
//type MemberClaims struct {
//	Username string `json:"username"`
//	jwt.StandardClaims
//}

type UserInfo struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

const TokenExpireDuration = time.Hour * 2
//var MemberSecret = []byte("你值得拥有")

// GenToken 生成JWT
func GenToken(username string) (string, error) {
	// 创建一个我们自己的声明
	c := model.MemberClaims{
		"username", // 自定义字段
		jwt.StandardClaims{
			ExpiresAt: time.Now().Add(TokenExpireDuration).Unix(), // 过期时间
			Issuer: "member-project",                               // 签发人
		},
	}
	// 使用指定的签名方法创建签名对象
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
	// 使用指定的secret签名并获得完整的编码后的字符串token
	return token.SignedString(model.MemberSecret)
}

//// ParseToken 解析JWT
//func ParseToken(tokenString string) (*model.MemberClaims, error) {
//	// 解析token
//	// token, err := jwt.Parse(tokenString, func(token *jwt.Token) (i interface{}, err error) {
//	// 	return MemberSecret, nil
//	// })
//
//	// 解析token
//	token, err := jwt.ParseWithClaims(tokenString, &model.MemberClaims{}, func(token *jwt.Token) (i interface{}, err error) {
//		return model.MemberSecret, nil
//	})
//	if err != nil {
//		return nil, err
//	}
//
//	// if token.Valid {
//	// 	fmt.Println(token.Claims) // 校验token
//	// 	return token.Claims.(*MemberClaims), nil   //报错
//	// }
//
//	if claims, ok := token.Claims.(*model.MemberClaims); ok && token.Valid { // 校验token
//		return claims, nil
//	}
//	return nil, errors.New("invalid token")
//}

func init(){
	orm.Debug = true
	orm.RegisterDataBase("default", "mysql", "root:new_password@tcp(127.0.0.1:3306)/orm_insert?charset=utf8")
	orm.RegisterModel(new(ProductType), new(Product), new(ProjectType), new(Project), new(Meal), new(Member))
    orm.RunSyncdb("default", false, true)
}

func (m *Many)Favicon(){
	return
}

func (m *Many)QueryMember(){

	//// 客户端携带Token有三种方式 1.放在请求头 2.放在请求体 3.放在URI
	//// 这里假设Token放在Header的Authorization中，并使用Bearer开头
	//// 这里的具体实现方式要依据你的实际业务情况决定
	//authHeader := m.Ctx.Input.Header("token")
	//if authHeader == "" {
	//	m.Data["json"] = map[string]interface{}{"message": "请求头中auth为空", "requestCode": 2003}
	//	m.ServeJSON()
	//	return
	//}
	//
	//// 按空格分割
	//parts := strings.SplitN(authHeader, " ", 2)
	//if !(len(parts) == 2 && parts[0] == "Bearer") {
	//	m.Data["json"] = map[string]interface{}{"message": "请求头中auth格式有误", "requestCode": 2004}
	//	m.ServeJSON()
	//	return
	//}
	//
	//// parts[1]是获取到的tokenString，我们使用之前定义好的解析JWT的函数来解析它
	//_, err := ParseToken(parts[1])
	//if err != nil {
	//	m.Data["json"] = map[string]interface{}{"message": "无效的Token", "requestCode": 2005}
	//	m.ServeJSON()
	//	return
	//}

	o := orm.NewOrm()
	var ms []*Member
	//b.Id = 2
	//o.Read(&b)
	//o.LoadRelated(&b, "UserList")
	//o.Raw("select * from blog where id = ?", 1).QueryRow(&b)
	var rms []Member
	o.Raw("select * from member where level <= ?", 80).QueryRows(&rms)
	fmt.Println("rms：", rms)
	o.QueryTable("member").All(&ms)
	for _, v := range ms{
		o.LoadRelated(v, "Meallist")
		//o.QueryTable("meal").Filter("MemberList__member__id", v.Id).All(&v.Meallist)
		for _, mv := range v.Meallist{
			o.LoadRelated(mv, "ProjectList")
			//o.LoadRelated(mv, "Memberlist")
			//o.QueryTable("project").Filter("MealList__meal__id", mv.Id).RelatedSel("Type").All(&mv.ProjectList)
			for _, jv := range mv.ProjectList{
				o.LoadRelated(jv, "Type")
				//o.LoadRelated(jv, "Meallist")
				//o.LoadRelated(jv.Type, "ProjectList")
			}

			o.LoadRelated(mv, "ProductList")
			//o.QueryTable("product").Filter("MealList__meal__id", mv.Id).All(&mv.ProductList)
			for _, dv := range mv.ProductList{
				o.LoadRelated(dv, "Type")
				//o.LoadRelated(dv, "Meallist")
				//o.LoadRelated(dv.Type, "ProductList")
			}
		}
	}

	m.Data["json"] = &ms
	m.ServeJSON()

}

func(m *Many)Login() {

	u := UserInfo{}
	if err := m.ParseForm(&u); err != nil{
		fmt.Println(err)
		return
	}
	fmt.Println("用户信息:", u)

	// 校验用户名和密码是否正确
	if u.Username == "yangliang" && u.Password == "yangliang123" {
		// 生成Token
		tokenString, _ := GenToken(u.Username)
		m.Data["json"] = map[string]interface{}{"message": "success", "code" : 2000, "token": tokenString}
		m.ServeJSON()
		return 
	}
	m.Data["json"] = map[string]interface{}{"message": "鉴权失败", "requestCode": 2002}
	m.ServeJSON()
	return
}

func main(){

	beego.BConfig.WebConfig.Session.SessionOn = true
	beego.Router("/queryMember", &Many{},"POST:QueryMember")
	beego.Router("/login", &Many{},"POST:Login")
	//beego.Router("/deleteMeal", &Many{},"GET:DeleteMeal")
	//beego.Router("/updateMeal", &Many{},"GET:UpdateMeal")
	beego.Router("/favicon.ico", &Many{},"*:Favicon")
	beego.Run()
}